import axios, { AxiosInstance } from 'axios';
// import type { AxiosResponse } from 'axios';
import type { xmRequestInterceptors, xmRequestConfig } from './type';

import { ElLoading } from 'element-plus';
import type { LoadingInstance } from 'element-plus/lib/components/loading/src/loading';

const DEFAULT_LOADING = true;
export default class xmRequest {
  interceptors?: xmRequestInterceptors;
  instance: AxiosInstance;
  loading?: LoadingInstance;
  showLoading: boolean;
  constructor(config: xmRequestConfig) {
    // console.log('constructor');
    this.interceptors = config.interceptors;
    this.instance = axios.create(config);
    this.showLoading = config?.showLoading ?? DEFAULT_LOADING; // 当showLoading为null或者undefined的时候  会使用后面的默认值

    // 构造函数通用拦截器、实例通用拦截器、实例单独拦截器   拦截器的执行顺序
    // 写入顺序的 倒序执行的
    this.instance.interceptors.request.use(
      this.interceptors?.requestInterceptor,
      this.interceptors?.requestInterceptorCatch,
    );

    this.instance.interceptors.response.use(
      this.interceptors?.reponseInterceptor,
      this.interceptors?.reponseInterceptorCatch,
    );

    this.instance.interceptors.request.use(
      (config) => {
        /**
         * 注意填写位置   如果写在constructor内 interceptors外 则直接调用生成
         * 因为构造实例时默认都是true的 所以后面实例本身不管传入什么都是无效的
         * 但当在interceptor内决定是否生成时  那么还是能被实例本身传入的数据判断
         *  */

        if (this.showLoading) {
          this.loading = ElLoading.service({
            lock: true,
            fullscreen: true,
          });
        }
        // console.log('所有实例通用请求成功拦截器');
        return config;
      },
      (err) => {
        // console.log('所有实例通用请求失败拦截器');
        return err;
      },
    );

    this.instance.interceptors.response.use(
      (res) => {
        setTimeout(() => {
          this.loading?.close();
        }, 1000);
        // console.log('所有实例通用响应成功拦截器');
        return res.data;
      },
      (err) => {
        this.loading?.close();
        // console.log('所有实例通用响应失败拦截器');
        return err;
      },
    );
  }

  request<T>(config: xmRequestConfig<T>): Promise<T> {
    // console.log('axios create request', config);
    // eslint-disable-next-line
    return new Promise((resolve, reject) => {
      this.showLoading = config?.showLoading ?? true;
      if (config.interceptors?.requestInterceptor) {
        config = config.interceptors.requestInterceptor(config);
      }

      this.instance
        .request<any, T>(config)
        .then((res) => {
          if (config.interceptors?.reponseInterceptor) {
            res = config.interceptors.reponseInterceptor(res);
          }
          // console.log(res);
          resolve(res);
        })
        .catch((err) => {
          reject(err);
        });
    });
  }

  get<T>(config: xmRequestConfig<T>): Promise<T> {
    return this.request({ ...config, method: 'GET' });
  }
  post<T>(config: xmRequestConfig<T>): Promise<T> {
    return this.request({ ...config, method: 'POST' });
  }
  delete<T>(config: xmRequestConfig<T>): Promise<T> {
    return this.request({ ...config, method: 'DELETE' });
  }
  patch<T>(config: xmRequestConfig<T>): Promise<T> {
    return this.request({ ...config, method: 'PATCH' });
  }
}
